from xmlrpc.server import SimpleXMLRPCServer,SimpleXMLRPCRequestHandler
import threading
from socketserver import ThreadingMixIn
import socket
import time
from socket import *
import rsa
import hashlib
import logging
import leveldb
from mpt_core.mpt import MerklePatriciaTree
from mpt_core.au import presense
from mpt_core.encoding import hexdigest_to_nib
from simchain.simchain.network import Network
from rsa_core.rsautil import *
import env
LEVELDBPATH = env.LEVELDBPATH
PUBLICKEYPATH = env.PUBLICKEYPATH
PRIVATEKEYPATH = env.PRIVATEKEYPATH
BLOCK_CHAIN_DB = env.BLOCK_CHAIN_DB
BROADCASTPOST = env.BROADCASTPORT
SERVER_HTTPRPC = env.SERVER_HTTPRPC
class ca_server(ThreadingMixIn,SimpleXMLRPCServer):
    def __init__(self,address):
        self._rpc_methods_ = ['register','create_proof_path','remove_authorization']
        self.data = {}
        self._serv = self._serv = SimpleXMLRPCServer(address, allow_none=True)
        for name in self._rpc_methods_:
            self._serv.register_function(getattr(self, name))
        self.MPT = MerklePatriciaTree(debug=False,from_scratch=True)
        self.MPT.init_new_root()
        self.pki_chain_net = Network(12)
        self.peer = self.pki_chain_net.peers[0]
        self.block_chain_db =  BLOCK_CHAIN_DB
        self.wallet = self.peer.wallet
        self.RsaUtil = RsaUtil(PUBLICKEYPATH,PRIVATEKEYPATH)
        self.public_key = self.RsaUtil.public_key
        self.private_key = self.RsaUtil.private_key
        self.encoding = "utf-8"  # 使用的编码方式
        self.broadcastPort = BROADCASTPOST  # 广播端口
        # 创建广播接收器
        self.recvSocket = socket(AF_INET, SOCK_DGRAM)
        self.recvSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.recvSocket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
        self.recvSocket.bind(('', self.broadcastPort))
        # 创建广播发送器
        self.sendSocket = socket(AF_INET, SOCK_DGRAM)
        self.sendSocket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
        # 其他
        self.threads = []
        self.auth = 0

    def register(self,data:dict):
        init_public_key = pickle.loads(base64.b64decode(data['public_key'].encode()))

        publick_key,private_key = rsa.newkeys(512)
        publick_key = publick_key.save_pkcs1().decode('utf-8')
        private_key = private_key.save_pkcs1().decode('utf-8')

        # 此处encrypt_public_key、encrypt_private_key是bytes的格式
        # 此处已经完成了CA->A/B的加密解密传输密钥的过程
        encrypt_public_key = self.encrypt_by_public_key(publick_key,init_public_key)
        encrypt_private_key = self.encrypt_by_public_key(private_key,init_public_key)

        key_nibble=hexdigest_to_nib(hashlib.sha256(publick_key.encode()).hexdigest())
        self.MPT.insert(key_nibble,publick_key)
        print("更新后MPT root_has:\n",self.MPT.root_hash)
        mpt_root_hash = self.MPT.root_hash.decode()
        # Notice: root_hash is a bytes object
        self.pki_chain_net.make_random_transactions(k=1,mpt_root_hash=self.MPT.root_hash)
        self.pki_chain_net.make_random_transactions(k=18,mpt_root_hash=None)
        block = ca.pki_chain_net.consensus()
        # 区块链的序列化有问题
        # selize_block = pickle.dumps(block)
        # print(selize_block)
        block_info = pickle.dumps('blockchainmessage' + block.__repr__())
        self.write_in_db(block)
        self.send(block_info)
        return encrypt_public_key.decode('utf-8'), encrypt_private_key.decode('utf-8'),mpt_root_hash


    def write_in_db(self,block):
        db = leveldb.LevelDB(self.block_chain_db)
        try:
            db.Put(block.merkle_root_hash.encode('utf-8'), pickle.dumps(block.__dict__()))
        except Exception as err:
            logging.info(err)

    def create_proof_path(self, data:dict):
        client_public_key = pickle.loads(base64.b64decode(data['public_key'].encode()))
        print("已经恢复公钥:\n",client_public_key)
        message = data['message']
        print("被签名信息:\n",message)
        signature = data['signature']
        print("签名:\n",signature)
        # 这块其实是要加密通信的
        if self.verify_by_public_key(message,signature,client_public_key):
            key_nibble = hexdigest_to_nib(hashlib.sha256(message.encode()).hexdigest())
            proof_path = presense(self.MPT.db,key_nibble)
            print("proof path:\n",proof_path)
            proof_path = base64.b64encode(pickle.dumps(proof_path)).decode()
            print("proof:",proof_path)
            print(type(proof_path))
            return proof_path
        else:
            return b''

    def remove_authorization(self,data:dict):
        client_public_key = pickle.loads(base64.b64decode(data['public_key'].encode()))
        message = data['message']
        signature = data['signature']
        if self.verify_by_public_key(message, signature, client_public_key):
            key_nibble = hexdigest_to_nib(hashlib.sha256(message.encode()).hexdigest())
            self.MPT.remove(key_nibble)
            self.pki_chain_net.make_random_transactions(k=1, mpt_root_hash=self.MPT.root_hash)
            self.pki_chain_net.make_random_transactions(k=18, mpt_root_hash=None)
            block = ca.pki_chain_net.consensus()
            block_info = pickle.dumps('blockchainmessage' + block.__repr__())
            self.write_in_db(block)
            self.send(block_info)
            return "You have been removed"
        else:
            return "You have not been removed"



    def sign_by_private_key(self):
        data = self.publickey.save_pkcs1().decode('utf-8')
        return self.RsaUtil.sign_by_private_key(data)

    def verify_by_public_key(self,message, signature, public_key):
        print("public output")
        if self.RsaUtil.verify_by_public_key(message, signature, public_key) == 'SHA-1':
            return True
        else:
            return False

    def encrypt_by_public_key(self, message,publick_key):
        return self.RsaUtil.encrypt_by_public_key(message,publick_key)
    # 这个函数很重要


    def serve_forever(self):
        self._serv.serve_forever()

    def send(self,data):
        """发送广播"""
        print("UDP发送器启动成功...")
        self.sendSocket.sendto(data, ('255.255.255.255', self.broadcastPort))
        # print("【%s】%s:%s" % (ctime(), "我", sendData))


    def start(self):
        """启动线程"""
        t2 = threading.Thread(target=self.send)
        t3 = threading.Thread(target=self.serve_forever())
        self.threads.append(t2)
        self.threads.append(t3)

        for t in self.threads:
            t.setDaemon(True)
            t.start()

INIT_PUBLIC = '''-----BEGIN RSA PUBLIC KEY-----
MEgCQQCb5L4wn9y/5n3zQ1QLdMIijmrGajI1rNpErLuIMSCFnxDKXLsQc9gDQbxE
FS36L7LXGcTZuMVdH4mo3Eux/w2lAgMBAAE=
-----END RSA PUBLIC KEY-----
'''

if __name__ == '__main__':
    ca = ca_server(SERVER_HTTPRPC)
    ca.start()
